package models

import (
	"crypto/md5"
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/util"
	"net/url"
	"strconv"
	"time"
)

type PayItem struct {
	FlowId          int64
	MemberId        int
	WaybillId       int
	BillAmount      float32
	InvoiceAmount   float32
	InsuranceAmount float32
	DepositAmount   float32
	TotalAmount     float32
	TypeId          int
	PayFor          int
	CardId          int
	State           int
	Remark          string
	TransNo         string
	WalletPwd       string
}

type PostPayItem struct {
	PayOk        bool
	Message      string
	CallbackData string
}

type PayParam struct {
	Pwd       string `json:"pay_pwd"`
	PayType   int    `json:"pay_type"`
	CardID    int    `json:"card_id"`
	WaybillId ID     `json:"waybill_id"`
}

type PayRS struct {
	PayId      ID         `json:"pay_id,omitempty"`
	PayType    int        `json:"pay_type"`
	PayAmount  float32    `json:"amount"`
	AllInPayRS AllInPayRS `json:"allinpay_param"`
	CreateTime string     `json:"create_time,omitempty"`
}

type QPayRS struct {
	PayID string `json:"pay_id"`
	State int    `json:"state"`
}

type PayAmountRS struct {
	Amount       float32 `json:"amount"`
	CanUseWallet bool    `json:"can_use_wallet"`
}

type TopUpRQ struct {
	Amount float32 `json:"amount"`
	PayPwd string  `json:"pay_pwd"`
}

type BankDetailListRS struct {
	TotalCount int            `json:"total_count"`
	List       []BankDetailRS `json:"bank_detail"`
}

type BankDetailRS struct {
	Amount     float32 `json:"amount"`
	TypeId     int     `json:"type_id"`
	Remark     string  `json:"remark"`
	CreateTime string  `json:"create_time"`
}

type TxFlowListRS struct {
	TotalCount int        `json:"total_count"`
	List       []TxFlowRS `json:"tx_flow"`
}

type TxFlowRS struct {
	FlowId     string  `json:"flow_id"`
	Amount     float32 `json:"amount"`
	State      string  `json:"state"`
	TypeId     int     `json:"type_id"`
	Remark     string  `json:"remark"`
	CreateTime string  `json:"create_time"`
}

type GetPaymentAmountDetailRQ struct {
	PayId string `json:"pay_id"`
}

type PayAmountDetail struct {
	DepositAmount   float32 `json:"deposit_amount"`
	BillAmount      float32 `json:"bill_amount"`
	InvoiceAmount   float32 `json:"invoice_amount"`
	InsuranceAmount float32 `json:"insurance_amount"`
	GuaranteeAmount float32 `json:"guarantee_amount"`
	TotalAmount     float32 `json:"total_amount"`
}

type NewPaymentAmount struct {
	BillAmount    float32
	CargoValue    float32
	NeedInvoice   bool
	NeedInsurance bool
}

type OfflinePayInfoRQ struct {
	WaybillID string `json:"waybill_id"`
}

type OfflinePayInfo struct {
	BankName    string `json:"bank_name"`
	BankCard    string `json:"bank_card"`
	PayeeName   string `json:"payee"`
	PayeeIDCard string `json:"payee_idcard"`
}

type QPayConfirmRQ struct {
	PayID   string `json:"pay_id"`
	SMSCode string `json:"sms_code"`
}

type Payment interface {
	PreTopUp(memberId int, amount float32) (payId ID, err error)
	PostTopUp(p data.PaymentDto, i PostPayItem) error
	PrePayDeposit(item PayItem) (depositPayId ID, err error)
	DoPayDeposit(payId ID) (interface{}, error)
	PostPayDeposit(p data.PaymentDto, i PostPayItem) error
	PrePayWaybill(item PayItem) (waybillPayId ID, err error)
	DoPayWaybill(payId ID) (interface{}, error)
	PostPayWaybill(p data.PaymentDto, i PostPayItem) error
	Confirm(memberID, payID ID, params string) error
}

func init() {
	go autoPaymentComplete()
}

func TopUp(memberId ID, pwd string, amount float32) (rs PayRS, err error) {
	var id int64
	if _, _, _, id, err = memberId.Decode(); err == nil {
		if amount > 0 {
			var repo data.PayRepo
			if _, err = repo.GetWalletWithPwd(int(id), pwd); err == nil {
				rs.PayAmount = amount
				rs.PayType = 1
				rs.PayId, err = getPayment(1).PreTopUp(int(id), amount)
				rs.CreateTime = time.Now().Format("20060102150405")
			} else {
				err = errors.New(errors.MSG_Wallet_Invalid_Pwd)
			}
		} else {
			err = errors.New(errors.MSG_Wallet_TopUp_Amount)
		}
	}
	return
}

func Refund(memberId, waybillId, refundFor int, amount, pBalanceAmount float32) (err error) {
	var flowId int64
	repo := &data.PayRepo{}
	if err = repo.BeginTx(); err == nil {
		defer func() {
			if err != nil {
				util.GetLogger().Error("[model-refund] - error%s", err.Error())
			}
			repo.EndTx(err == nil)
		}()
		if flowId, err = repo.NewTransFlow(data.TransFlowDto{
			MemberId:   memberId,
			TransNo:    fmt.Sprintf("%x", md5.Sum([]byte(string(waybillId)))),
			Amount:     amount,
			State:      1,
			TypeId:     4,
			Remark:     "退款",
			CreateTime: time.Now(),
		}); err == nil {
			if err = repo.NewRefund(data.RefundDto{
				FlowId:     flowId,
				MemberId:   memberId,
				WaybillId:  waybillId,
				Amount:     amount,
				RefundFor:  refundFor,
				Remark:     "",
				State:      1,
				CreateTime: time.Now(),
			}); err == nil {
				var w Wallet
				w.repo = repo
				err = w.TopUp(memberId, 4, waybillId, flowId, amount, pBalanceAmount, 0, false, "")
			}
		}
	}
	return
}

func Pay(memberId, waybillId ID, walletPwd, rcvUrl string, payType, cardID int) (rs interface{}, err error) {
	var paid bool
	var mId, wId int64
	if _, _, _, mId, err = memberId.Decode(); err != nil {
		util.GetLogger().Error("[wallet-Pay] - error:unexpected mbrId:%s", string(memberId))
		return
	}

	if _, _, _, wId, err = waybillId.Decode(); err != nil {
		util.GetLogger().Error("[wallet-Pay] - error:unexpected waybillId:%s", string(waybillId))
		return
	}

	var orderRepo data.OrderRepo
	var waybillDto data.WaybillDetailDto
	if waybillDto, err = orderRepo.GetWaybillDetail(int(wId)); err == nil {
		if int(mId) != waybillDto.CargoOwnerId {
			err = errors.New(errors.MSG_Pay_Not_Same_Payer)
			return
		}
	}

	payRepo := &data.PayRepo{}
	var payFor = 0
	if waybillDto.State == 3 {
		payFor = 1
	}
	if paid, err = payRepo.CheckPaid(int(wId), payFor); err == nil {
		if !paid {
			var walletDto data.WalletDto
			if walletDto, err = payRepo.GetWalletWithPwd(int(mId), walletPwd); err == nil {
				if waybillDto.State == 0 {
					rs, err = PayDeposit(int(wId), waybillDto, walletDto.Balance, walletPwd, payType, cardID, rcvUrl, "测试")
				} else if waybillDto.State == 3 {
					rs, err = PayWaybill(int(wId), waybillDto, walletDto.Balance, walletPwd, payType, cardID, rcvUrl, "测试")
				} else {
					err = errors.New(errors.MSG_Pay_Invalid_State)
				}
			} else {
				util.GetLogger().Error("[model-Pay] - error:%s", err.Error())
				err = errors.New(errors.MSG_Pay_Error)
			}
		} else {
			err = errors.New(errors.MSG_Pay_Already_Paid)
		}
	} else {
		util.GetLogger().Error("[model-Pay] - error:%s", err.Error())
		err = errors.New(errors.MSG_Pay_Error)
	}

	return
}

func PayDeposit(waybillId int, waybillDto data.WaybillDetailDto, walletBalance float32, walletPwd string, payType, cardID int, rcvUrl, productName string) (rs interface{}, err error) {
	var ok bool
	var payID ID
	var paymentDto data.PaymentDto

	repo := new(data.PayRepo)

	var general General
	var minDepositAmount float64
	if minDepositAmount, err = strconv.ParseFloat(general.GetParams("min_deposit_amount"), 32); err == nil {
		if float64(waybillDto.Deposit) < minDepositAmount {
			err = errors.New(fmt.Sprintf("%s%v元", errors.MSG_Order_Deposit_Amount_Not_Less_Than, minDepositAmount))
			return
		}
	}

	if paymentDto, ok, err = repo.GetUnpaid(waybillId); err == nil {
		if !ok {
			//客户端提交没选择支付方式
			if payType == -1 {
				rs = &PayAmountRS{Amount: waybillDto.Deposit, CanUseWallet: walletBalance >= waybillDto.Deposit}
			} else {
				payment := getPayment(payType)
				if payID, err = payment.PrePayDeposit(PayItem{
					MemberId:        waybillDto.CargoOwnerId,
					WaybillId:       waybillId,
					DepositAmount:   waybillDto.Deposit,
					BillAmount:      0,
					InvoiceAmount:   0,
					InsuranceAmount: 0,
					TotalAmount:     waybillDto.Deposit,
					TypeId:          payType,
					PayFor:          0,
					CardId:          cardID,
					TransNo:         fmt.Sprintf("%x", md5.Sum([]byte(string(waybillId)))),
					WalletPwd:       walletPwd,
				}); err == nil {
					rs, err = payment.DoPayDeposit(payID)
				}
			}
		} else {
			payment := getPayment(paymentDto.TypeId)
			payID.Encode(ID_Shard, ID_Ver, ID_Payment_Category, int64(paymentDto.Id))
			rs, err = payment.DoPayDeposit(payID)
		}
	} else {
		util.GetLogger().Error("[model-payDepost] - error%s", err.Error())
		err = errors.New(errors.MSG_Pay_Error)
	}

	return
}

func PayWaybill(waybillId int, waybillDto data.WaybillDetailDto, walletBalance float32, walletPwd string, payType, cardID int, rcvUrl, productName string) (rs interface{}, err error) {
	var ok bool
	var payID ID
	var general General
	var minPriceAmount float64
	var invoiceAmount, ratioInsuranceAmount float32
	var minInsuranceAmount, fixedInsuranceAmount float64
	var paymentDto data.PaymentDto
	repo := &data.PayRepo{}

	if minPriceAmount, err = strconv.ParseFloat(general.GetParams("min_price_amount"), 32); err == nil {
		if float64(waybillDto.Price) < minPriceAmount {
			err = errors.New(fmt.Sprintf("%s%v元", errors.MSG_Order_Price_Amount_Not_Less_Than, minPriceAmount))
			return
		}
	}

	if paymentDto, ok, err = repo.GetUnpaid(waybillId); err == nil {
		if !ok {
			var ratio float64
			var general General
			if waybillDto.NeedInsurance {
				if ratio, err = strconv.ParseFloat(general.GetParams("insurance_ratio"), 32); err == nil {
					ratioInsuranceAmount = float32(util.FormatAmount(float64(waybillDto.CargoValue) * ratio))
					if minInsuranceAmount, err = strconv.ParseFloat(general.GetParams("min_insurance_amount"), 32); err == nil {
						if float64(ratioInsuranceAmount) < minInsuranceAmount {
							ratioInsuranceAmount = float32(minInsuranceAmount)
						}
					}
				}
				fixedInsuranceAmount, err = strconv.ParseFloat(general.GetParams("insurance_fixed_amount"), 32)

				var insuranceRepo data.InsuranceRepo
				if ok, err = insuranceRepo.CheckNotInsured(waybillId); err == nil {
					if ok {
						records := make([]InsuranceRecord, 2)
						records[0] = InsuranceRecord{
							MemberId:  waybillDto.CargoOwnerId,
							WaybillId: waybillId,
							Amount:    ratioInsuranceAmount,
							TypeId:    0,
							AgentId:   0,
							ReqData:   "",
						}
						records[1] = InsuranceRecord{
							MemberId:  waybillDto.CargoOwnerId,
							WaybillId: waybillId,
							Amount:    float32(fixedInsuranceAmount),
							TypeId:    1,
							AgentId:   1,
							ReqData:   "",
						}

						if err = PreInsure(records); err != nil {
							util.GetLogger().Error("[model-payWaybill] - error%s", err.Error())
							err = errors.New(errors.MSG_Pay_Error)
							return
						}
					}
				} else {
					util.GetLogger().Error("[model-payWaybill] - error%s", err.Error())
					err = errors.New(errors.MSG_Pay_Error)
					return
				}
			}

			if waybillDto.NeedInvoice {
				if ratio, err = strconv.ParseFloat(general.GetParams("invoice_ratio"), 32); err == nil {
					total := waybillDto.Deposit + waybillDto.Price
					invoiceAmount = float32(util.FormatAmount(float64(total)/ratio - float64(total)))
					var orderRepo data.OrderRepo
					if err = orderRepo.UpdateInvoiceAmount(waybillId, float32(util.FormatAmount(float64(total)/ratio)), ratioInsuranceAmount, float32(fixedInsuranceAmount)); err != nil {
						return
					}
				}
			}

			totalAmount := waybillDto.Price + invoiceAmount + ratioInsuranceAmount + float32(fixedInsuranceAmount)
			if payType == -1 {
				rs = &PayAmountRS{Amount: totalAmount, CanUseWallet: walletBalance >= totalAmount}
			} else {
				payment := getPayment(payType)
				if payID, err = payment.PrePayWaybill(PayItem{
					MemberId:        waybillDto.CargoOwnerId,
					WaybillId:       waybillId,
					BillAmount:      waybillDto.Price,
					InvoiceAmount:   invoiceAmount,
					InsuranceAmount: ratioInsuranceAmount + float32(fixedInsuranceAmount),
					TotalAmount:     totalAmount,
					TypeId:          payType,
					PayFor:          1,
					TransNo:         fmt.Sprintf("%x", md5.Sum([]byte(string(waybillId)))),
					WalletPwd:       walletPwd,
					CardId:          cardID,
				}); err == nil {
					rs, err = payment.DoPayWaybill(payID)
				}
			}
		} else {
			payment := getPayment(paymentDto.TypeId)
			payID.Encode(ID_Shard, ID_Ver, ID_Payment_Category, int64(paymentDto.Id))
			rs, err = payment.DoPayWaybill(payID)
		}
	} else {
		util.GetLogger().Error("[model-payWaybill] - error%s", err.Error())
		err = errors.New(errors.MSG_Pay_Error)
	}

	return
}

func PayConfirm(memberID, payID ID, payType int, params string) error {
	return getPayment(payType).Confirm(memberID, payID, params)
}

func PostPay(payId ID, amount float32, i PostPayItem) (err error) {
	var p data.PaymentDto
	if p, err = getPaymentDetail(payId, amount); err == nil {
		if p.State == 0 {
			var o Order
			var memberId, waybillId ID
			memberId.Encode(ID_Shard, ID_Ver, ID_Member_Category, int64(p.MemberId))
			waybillId.Encode(ID_Shard, ID_Ver, ID_Waybill_Category, int64(p.WaybillId))

			if p.PayFor == 0 {
				if err = getPayment(p.TypeId).PostPayDeposit(p, i); err == nil && i.PayOk {
					err = o.UpdateWaybillState(memberId, &UpdateWaybillStateWithParamsRQ{Id: waybillId, State: 1})
				}
			} else if p.PayFor == 1 {
				if err = getPayment(p.TypeId).PostPayWaybill(p, i); err == nil && i.PayOk {
					err = o.UpdateWaybillState(memberId, &UpdateWaybillStateWithParamsRQ{Id: waybillId, State: 4})
				}
			} else if p.PayFor == 2 {
				err = getPayment(p.TypeId).PostTopUp(p, i)
			}
		} else {
			err = errors.New(errors.MSG_Pay_Callback_Duplicated)
		}
	}
	return
}

// AutoPayOnlyForTest ...
func AutoPayOnlyForTest(memberID, payID ID) (err error) {
	var mid, pid int64
	var dto data.PaymentDto
	if _, _, _, mid, err = memberID.Decode(); err != nil {
		return err
	}
	if _, _, _, pid, err = payID.Decode(); err != nil {
		return err
	}
	var repo data.PayRepo
	if dto, err = repo.GetPaymentDetailById(int(pid), int(mid)); err == nil {
		err = PostPay(payID, dto.TotalAmount, PostPayItem{PayOk: true})
	}
	return
}

func GetBankDetailList(memberId ID, pageNo, pageSize int) (rs BankDetailListRS, err error) {
	var id, cnt int64
	var repo data.PayRepo
	var list []data.BankDetailDto
	if _, _, _, id, err = memberId.Decode(); err == nil {
		if list, cnt, err = repo.GetBankDetailList(int(id), pageNo, pageSize); err == nil {
			rs.TotalCount = int(cnt)
			rs.List = make([]BankDetailRS, len(list))
			for idx, val := range list {
				rs.List[idx] = BankDetailRS{
					Amount:     val.Amount,
					TypeId:     val.TypeId,
					Remark:     val.Remark,
					CreateTime: val.CreateTime,
				}
			}
		}
	} else {
		util.GetLogger().Error("[pay-GetBankPayDetailList] - error:unexpected mbrId:%s", string(memberId))
		err = errors.New(errors.MSG_Pay_Get_Bank_Detail_Error)
	}
	return
}

func GetTransFlowList(memberId ID, pageNo, pageSize int) (rs TxFlowListRS, err error) {
	var id, cnt int64
	var repo data.PayRepo
	var list []data.TransFlowDto
	if _, _, _, id, err = memberId.Decode(); err == nil {
		if list, cnt, err = repo.GetTransFLowList(int(id), pageNo, pageSize); err == nil {
			rs.TotalCount = int(cnt)
			rs.List = make([]TxFlowRS, len(list))
			for idx, val := range list {
				rs.List[idx] = TxFlowRS{
					FlowId:     fmt.Sprintf("%s%02d%02s%011d", val.CreateTime.Format("20060102"), val.TypeId, "1", val.Id),
					Amount:     val.Amount,
					TypeId:     val.TypeId,
					Remark:     val.Remark,
					CreateTime: val.CreateTime.Format("2006-01-02 15:04:05"),
				}
				if val.State == 0 {
					rs.List[idx].State = "未完成"
				} else if val.State == 1 {
					rs.List[idx].State = "成功"
				} else {
					rs.List[idx].State = "失败"
				}
			}
		}
	} else {
		util.GetLogger().Error("[pay-GetBankPayDetailList] - error:unexpected mbrId:%s", string(memberId))
		err = errors.New(errors.MSG_Pay_Get_Bank_Detail_Error)
	}
	return
}

func UpdatePlatformBalance(waybillId int) (err error) {
	var list []data.InsuranceDto
	var pBalances []data.PlatformBalanceDto
	var paymentDto data.PaymentDto
	var insuranceRepo data.InsuranceRepo
	repo1 := &data.PayRepo{}
	repo2 := data.PayRepo{}
	if pBalances, err = repo1.GetPlatformBalances([]int{2, 3, 4}); err == nil {
		if paymentDto, err = repo2.GetPaymentDetailByWaybillId(waybillId, 1, 1); err == nil {
			if paymentDto.TotalAmount > 0 {
				if paymentDto.InvoiceAmount > 0 {
					doUpdatePlatformBalance(pBalances[0], paymentDto.InvoiceAmount)
				}
				if paymentDto.InsuranceAmount > 0 {
					if list, err = insuranceRepo.GetCompleteInsurance(waybillId); err == nil {
						for _, v := range list {
							if v.TypeId == 0 {
								if v.Amount > 0 {
									err = doUpdatePlatformBalance(pBalances[1], v.Amount)
								}
							} else {
								if v.Amount > 0 {
									err = doUpdatePlatformBalance(pBalances[2], v.Amount)
								}
							}
						}
					}
				}
			}
		}
	}
	return
}

func GetPaymentAmountDetail(payId, memberId ID) (p PayAmountDetail, err error) {
	var paymentDto data.PaymentDto
	var repo data.PayRepo
	var pid, mid int64
	if _, _, _, pid, err = payId.Decode(); err != nil {
		err = errors.New(errors.MSG_Pay_Invalid_ID)
		return
	}

	if _, _, _, mid, err = memberId.Decode(); err != nil {
		err = errors.New(errors.MSG_Mbr_Invalid)
		return
	}

	if paymentDto, err = repo.GetPaymentDetailById(int(pid), int(mid)); err == nil {
		p, err = getPaymentAmountDetail(paymentDto)
	} else {
		util.GetLogger().Error("[model-GetPaymentAmountDetail] - error:%s", err.Error())
	}

	return
}

func GetPaymentAmountDetailByWaybillId(waybillId int) (p PayAmountDetail, err error) {
	var repo data.PayRepo
	var paymentDto data.PaymentDto
	if paymentDto, err = repo.GetPaymentDetailByWaybillId(waybillId, 1, 1); err == nil {
		p, err = getPaymentAmountDetail(paymentDto)
	} else {
		util.GetLogger().Error("[model-GetPaymentAmountDetailByWaybillId] - error:%s", err.Error())
	}
	return
}

func getPaymentAmountDetail(paymentDto data.PaymentDto) (p PayAmountDetail, err error) {
	var list []data.InsuranceDto
	var insuranceRepo data.InsuranceRepo
	p = PayAmountDetail{
		DepositAmount: paymentDto.DepositAmount,
		BillAmount:    paymentDto.BillAmount,
		InvoiceAmount: paymentDto.InvoiceAmount,
		TotalAmount:   paymentDto.TotalAmount,
	}
	if paymentDto.InsuranceAmount != 0 {
		if list, err = insuranceRepo.GetInsurancePayAmount(paymentDto.WaybillId); err == nil {
			for _, val := range list {
				if val.TypeId == 0 {
					p.InsuranceAmount = val.Amount
				} else {
					p.GuaranteeAmount = val.Amount
				}
			}
		} else {
			util.GetLogger().Error("[model-GetPaymentAmountDetail] - error:%s", err.Error())
		}
	}

	return
}

func CancelPaymentIfAny(waybillId int) (err error) {
	var repo data.PayRepo
	var paymentDto data.PaymentDto
	if paymentDto, err = repo.GetPaymentDetailByWaybillId(waybillId, 1, 0); err == nil {
		err = repo.Cancel(paymentDto.Id)
	}
	return
}

func AddReward(memberId, waybillId int) (err error) {
	var flowId int64
	var rewardAmount float64
	var general General
	var pBalance data.PlatformBalanceDto
	if rewardAmount, err = strconv.ParseFloat(general.GetParams("reward_fixed_amount"), 32); err == nil {
		repo := &data.PayRepo{}
		repo.BeginTx()
		defer func() {
			if err != nil {
				util.GetLogger().Error("[model-AddReward] - error%s", err.Error())
			}
			repo.EndTx(err == nil)
		}()

		if flowId, err = repo.NewTransFlow(data.TransFlowDto{
			MemberId: memberId,
			TransNo:  fmt.Sprintf("%x", md5.Sum([]byte(string(waybillId)))),
			Amount:   float32(rewardAmount),
			TypeId:   5,
			State:    1,
			Remark:   "推广奖励",
		}); err == nil {
			if err = repo.NewReward(data.RewardDto{
				FlowId:    flowId,
				MemberId:  memberId,
				WaybillId: waybillId,
				Amount:    float32(rewardAmount),
			}); err == nil {
				if pBalance, err = repo.GetPlatformBalanceById(7); err == nil {
					repo.AddAndUpdatePlatformBalance(pBalance, flowId, float32(rewardAmount), 1)
				}
			}
		}
	}
	return
}

func GetOfflinePayInfoList(memberID ID) (payInfo []OfflinePayInfo, err error) {
	var mid int64
	if _, _, _, mid, err = memberID.Decode(); err != nil {
		err = errors.New(errors.MSG_Mbr_Invalid)
		return
	}

	var repo data.PayRepo
	var list []data.PayOfflineDto

	if list, err = repo.GetOfflinePayInfoList(int(mid)); err != nil {
		util.GetLogger().Error("[GetLastOfflinePayInfo] - error:%s", err.Error())
		err = errors.New(errors.MSG_Pay_Invalid_Offline)
	} else {
		payInfo = make([]OfflinePayInfo, len(list))
		for i, val := range list {
			payInfo[i] = OfflinePayInfo{
				PayeeName:   val.PayeeName,
				PayeeIDCard: val.PayeeIDCard,
				BankName:    val.BankName,
				BankCard:    val.BankCard,
			}
		}
	}
	return
}

func GetOfflinePayInfoByWaybillID(waybillID ID) (payInfo OfflinePayInfo, err error) {
	var wid int64
	if _, _, _, wid, err = waybillID.Decode(); err != nil {
		err = errors.New(errors.MSG_Order_Invalid_Waybill)
		return
	}

	var repo data.PayRepo
	var dto data.PayOfflineDto

	if dto, err = repo.GetOfflinePayInfo(int(wid)); err != nil {
		util.GetLogger().Error("[GetOfflinePayInfo] - error:%s", err.Error())
		err = errors.New(errors.MSG_Pay_Invalid_Offline)
	} else {
		payInfo.PayeeName = dto.PayeeName
		payInfo.BankName = dto.BankName
		payInfo.BankCard = dto.BankCard
		payInfo.PayeeIDCard = dto.PayeeIDCard
	}
	return
}

func doUpdatePlatformBalance(p data.PlatformBalanceDto, amount float32) error {
	repo := &data.PayRepo{}
	oldBalance := p.Balance
	p.Balance = p.Balance + amount
	return repo.UpdatePlatformBalance(&p, oldBalance)
}

func getPayment(payType int) Payment {
	var payment Payment
	if payType == 0 {
		payment = &WalletPay{}
	} else if payType == 1 {
		payment = &GatewayPay{}
	} else if payType == 99 {
		payment = &GatewayPayMock{}
	}
	return payment
}

func getPaymentDetail(payId ID, amount float32) (detail data.PaymentDto, err error) {
	var paymentId int64
	var repo data.PayRepo
	if _, _, _, paymentId, err = payId.Decode(); err == nil {
		detail, err = repo.GetPaymentDetailByIdWithAmount(int(paymentId), amount)
	}
	return
}

func autoPaymentComplete() {
	var repo data.PayRepo
	t1 := time.NewTimer(10 * time.Second)
	for {
		select {
		case <-t1.C:
			util.GetLogger().Info("start payment auto complete")
			if ps, err := repo.GetNotCompletePaymentToPost(); err == nil {
				for _, p := range ps {
					util.GetLogger().Info("begin payment auto complete. id:%d", p.Id)
					var payId ID
					payId.Encode(ID_Shard, ID_Ver, ID_Payment_Category, int64(p.Id))
					if result, err := post_allinpay_query(string(payId), p.CreateTime.Format("20060102150405")); err == nil {
						if vals, err := url.ParseQuery(result); err == nil {
							if vals.Get("errorCode") == "" {
								if amount, err := strconv.ParseFloat(vals.Get("payAmount"), 32); err == nil {
									payId := vals.Get("orderNo")
									if err := PostPay(ID(payId), float32(amount)/100, PostPayItem{PayOk: true, Message: "", CallbackData: result}); err != nil {
										util.GetLogger().Error("[ctrl-PostPay] - error:%s. [id:%s] ", err.Error(), payId)
									}
								}
							}
						} else {
							util.GetLogger().Error("[model-autoPaymentComplete] - error:%s", err.Error())
						}
					} else {
						util.GetLogger().Error("[model-autoPaymentComplete] - error:%s", err.Error())
					}
					if len(ps) > 100 {
						time.Sleep(2 * time.Second)
					}
				}
			}
			t1.Reset(10 * time.Second)
		}
	}
}
